from fastapi import APIRouter, Body, UploadFile
from ..model.infer import Lot, InferPanel, InferPanelImage, Failure, Material, ScpJob
from sqlalchemy import and_
import json
import math
from sqlalchemy import func
from ..utils.database import InferSessionLocal
from ..utils.post_item import AOILotItem, AOIImageItem, PanelItem, PanelJudgeItem, AOILotDetailItem, FailureImageItem, LotDeleteItem, AOILotUniqItem, PanelExportItem, SelectPanelCodeItem, UploadCsvItem, PanelImageItem, PanelParetoItem, LogItem, LotRenameItem, PanelMesJudgeItem
from decimal import Decimal
import shutil
import os
from datetime import timedelta
from ..config import thumb_dir, lot_dir, out_dir, yolox_model_path1, yolox_model_path2, yolox_model_path3, thread_num, cls_forWhite_model_path, cls_forRules_model_path, jd_package, Config
from typing import List
from ..job.lot_job import update_lot_from_csv, panel_export_task, export_csv_task, failure_image_task, panel_pareto_task, panel_box_heatmap_task, panel_pixel_heatmap_task
from .. import loop
from ..utils.log import json_logger
from ..utils.lot import get_material_name, get_material_lots, get_aoi_name, panel_failure_data, lot_code_filter, panel_filter, lot_filter
from datetime import datetime

router = APIRouter()

# src 
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# get all lot
@router.post('/all-lots')
async def get_all_lots(item: AOILotItem):
    # 从数据库中获取所有的 lot 数据
    page_index = item.page_index
    page_size = item.page_size
    lot_name = item.lot_name
    res = {}

    offset_data = page_size * (page_index-1)

    with InferSessionLocal() as session:
        if lot_name:
            lot_num = session.query(func.count(Lot.lot_code)).filter(Lot.lot_name.like("%" + lot_name + "%")).scalar()
            lot_paginate = session.query(Lot).filter(Lot.lot_name.like("%" + lot_name + "%")).order_by(Lot.start_time.desc()).offset(offset_data).limit(page_size)
        else:
            lot_num = session.query(func.count(Lot.lot_code)).scalar()
            lot_paginate = session.query(Lot).order_by(Lot.start_time.desc()).offset(offset_data).limit(page_size)

        lot_data = []

        for lot in lot_paginate.all():
            lot_item = {}
            lot_item["lot_name"] = lot.lot_name
            lot_item["lot_code"] = lot.lot_code
            lot_item["status"] = lot.status

            lot_data.append(lot_item)

        res["data"] = lot_data
        res["lot_num"] = lot_num

        return res


# 人工复检,lot 名称下拉框
@router.post('/lots')
async def get_lots(item: AOILotUniqItem):
    # 从数据库中获取所有的 lot 数据并对 lotname 去重
    # 模糊查询
    lot_name = item.lot_name
    is_complete = item.is_complete
    res = {}

    with InferSessionLocal() as session:
        if lot_name:
            lots = session.query(Lot).filter(Lot.lot_name.like("%" + lot_name + "%")).order_by(Lot.start_time.desc())
        else:
            lots = session.query(Lot).order_by(Lot.start_time.desc())

        if is_complete:
            lots = lots.filter(Lot.status == '1')

        lot_data = []

        for lot in lots.all():
            panel_num = session.query(func.count(InferPanel.panel_code)).filter(InferPanel.lot_code == lot.lot_code).scalar()

            if (lot.lot_name in lot_data) or (panel_num==0):
                continue

            if is_complete:
                lot_data.append({"lotname": lot.lot_name, "end_time": lot.end_time.strftime('%Y-%m-%d %H:%M:%S'), "lot_code": lot.lot_code})
            else:
                lot_data.append({"lotname": lot.lot_name, "lot_code": lot.lot_code})

        res["data"] = lot_data

        return res


# 按 lot 显示 -> 删除 lot
@router.post('/lot-delete')
async def lot_delete(item: LotDeleteItem):
    # 从数据库中获取所有的 lot 数据
    lot_codes = item.lot_code
    is_error = False

    with InferSessionLocal() as session:
        
        lots = session.query(Lot).filter(Lot.lot_code.in_(lot_codes)).all()

        # 如果删除本地文件报错,继续删除 mysql
        try:
            # 删除本地文件
            for lot in lots:
                des_lot_dir = lot.dir_path
                out_lot_dir = des_lot_dir.replace(lot_dir, out_dir)
                thumb_folder = des_lot_dir.replace(lot_dir, thumb_dir)

                shutil.rmtree(des_lot_dir)
                shutil.rmtree(out_lot_dir)
                shutil.rmtree(thumb_folder)

        except Exception:
            is_error = True
        
        # 删除数据库中的 lot
        session.query(Lot).filter(Lot.lot_code.in_(lot_codes)).delete()

        # 删除数据库中的 panel image
        session.query(InferPanel).filter(InferPanel.lot_code.in_(lot_codes)).delete()

        # 删除数据库中的 failure image
        session.query(InferPanelImage).filter(InferPanelImage.lot_code.in_(lot_codes)).delete()

        # 删除数据库中的 scp job
        session.query(ScpJob).filter(ScpJob.lot_code.in_(lot_codes)).delete()

        session.commit()

        if is_error:
            return {"code": 0, "message": "删除 lot 出错"}

        return {"code": 0, "message": "删除 lot 成功"}


# 结果详情,按 lot 显示
@router.post('/lot-detail')
async def lot_detail(item: AOILotDetailItem):
    page_index = item.page_index
    page_size = item.page_size
    lot_name = item.lot_name
    end_time = item.end_time 
    start_time = item.start_time
    material_names = item.material_names

    res = {}
    offset_data = page_size * (page_index-1)

    with InferSessionLocal() as session:

        lots = lot_filter(session, lot_name=lot_name, start_time=start_time, end_time=end_time, material_names=material_names)

        total_num = len(lots.all())

        lot_paginate = lots.order_by(Lot.start_time.desc()).offset(offset_data).limit(page_size).all()

        lot_data = []

        for lot in lot_paginate:
            lot_item = {}
            lot_item["lot_name"] = lot.lot_name
            lot_item["lot_code"] = lot.lot_code
            lot_item["status"] = lot.status
            lot_item["material_name"] = get_material_name(lot.material_code)
            lot_item["aoi_name"] = get_aoi_name(lot.aoi_code) if lot.aoi_code else ""
            lot_item["start_time"] = lot.start_time.strftime('%Y-%m-%d %H:%M:%S')
            lot_item["end_time"] = lot.end_time.strftime('%Y-%m-%d %H:%M:%S') if lot.end_time else ""
            lot_item["comment"] = lot.comment

            panels = session.query(InferPanel).filter(InferPanel.lot_code == lot.lot_code)

            panel_num = session.query(func.count(InferPanel.panel_code)).filter(InferPanel.lot_code == lot.lot_code).scalar()
            
            aoi_accuracy = 0
            ai_accuracy = 0

            ai_gray = 0
            ai_ng = 0

            judgment_same = 0
            judgment_diff = 0
            judgment_no = 0
            judgment_other = 0

            judgement_accuracy = 0

            ai_missdetect = 0
            ai_overdetect = 0
            ai_overdetect_ng = 0
            ai_overdetect_gray = 0

            for panel in panels:
                aoi_result = panel.aoi_result
                ai_result = panel.ai_result
                judgment = panel.judgment

                # 如果 aoi 检测是正确的图片
                if aoi_result == 1:
                    aoi_accuracy += 1

                # 如果 ai 检测是正确的图片
                if ai_result == 1:
                    ai_accuracy += 1
                elif ai_result == 3:
                    ai_gray += 1
                else:
                    ai_ng += 1


                # 判断人工复检结果
                if ai_result == judgment:
                    judgment_same += 1
                else:
                    # 未复判
                    if judgment == 0:
                        judgment_no += 1
                    # 其它情况
                    elif judgment == 3:
                        judgment_other += 1
                    # 人工复判：OK, ai: Gray, NG
                    elif judgment == 1:
                        # ai 过检
                        ai_overdetect += 1
                        judgment_diff += 1
                        # ai: Gray
                        if ai_result == 3:
                            ai_overdetect_gray += 1
                        else:
                            ai_overdetect_ng += 1
                    # 人工复判：NG, ai: Gray, OK
                    else:
                        # ai: Gray
                        if ai_result == 3:
                            judgment_same += 1
                        # ai: OK
                        else:
                            # ai 漏检
                            ai_missdetect += 1
                            judgment_diff += 1

                if judgment == 1:
                    judgement_accuracy += 1

            lot_item["panel_num"] = panel_num

            if panel_num == 0:
                lot_data.append(lot_item)
                continue

            lot_item["aoi_accuracy_rate"] = int(Decimal(aoi_accuracy/panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            lot_item["aoi_accuracy"] = aoi_accuracy
            lot_item["aoi_error"] = panel_num - aoi_accuracy

            # ai 良品率
            lot_item["ai_accuracy_rate"] = int(Decimal(ai_accuracy/panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            # ai 良品数量
            lot_item["ai_accuracy"] = ai_accuracy

            # ai 不良数量
            lot_item["ai_error"] = panel_num - ai_accuracy
            lot_item["ai_gray"] = ai_gray
            lot_item["ai_ng"] = ai_ng

            lot_item["judgment_same"] = judgment_same
            lot_item["judgment_diff"] = judgment_diff
            lot_item["judgment_no"] = judgment_no
            lot_item["judgment_other"] = judgment_other

            lot_item["judgement_accuracy"] = int(Decimal(judgement_accuracy/panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)

            # ai 过检率
            lot_item["ai_overdetect_rate"] = int(Decimal(ai_overdetect/panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            lot_item["ai_overdetect"] = ai_overdetect
            lot_item["ai_overdetect_gray"] = ai_overdetect_gray
            lot_item["ai_overdetect_gray_rate"] = int(Decimal(ai_overdetect_gray/panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            lot_item["ai_overdetect_ng"] = ai_overdetect_ng
            lot_item["ai_overdetect_ng_rate"] = int(Decimal(ai_overdetect_ng/panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)

            lot_item["ai_missdetect_rate"] = int(Decimal(ai_missdetect/panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            lot_item["ai_missdetect"] = ai_missdetect

            lot_data.append(lot_item)

        res["lot"] = lot_data

        res["total_num"] = total_num

        return res


@router.get('/failure-type')
async def failure_type():
    all_failure_type = {}
    with InferSessionLocal() as session:
        failures = session.query(Failure).filter_by(del_flag="0").all()
        for failure in failures:
            all_failure_type[failure.failure_id] = [failure.failure_name, failure.failure_type]
        return {"failure_types": all_failure_type}


@router.post('/panel-pareto')
async def panel_pareto(item: PanelParetoItem):
    end_time = item.end_time
    start_time = item.start_time
    material_names = item.material_names

    res = await loop.run_in_executor(None, panel_pareto_task, start_time, end_time, material_names)

    return {"predict_data": res}


# 结果详情 -> 按 panel 显示
@router.post('/panel-image')
async def panel_image(item: PanelImageItem):
    page_index = item.page_index
    page_size = item.page_size
    lot_names = item.lot_names
    lot_code = item.lot_code
    panel_ids = item.panel_ids
    failure_ids = item.failure_ids
    # 综合判定结果
    judgments = item.judgments if item.judgments else []
    end_time = item.end_time
    start_time = item.start_time
    ai_result = item.ai_result
    aoi_result = item.aoi_result
    # 人工复盘结果
    pjudgment = item.pjudgment

    # aoi生成的 panel 时间
    aoi_start_time = item.aoi_start_time
    aoi_end_time = item.aoi_end_time


    with InferSessionLocal() as session:
        panel_images = panel_filter(session, lot_names=lot_names, lot_code=lot_code, panel_ids=panel_ids, failure_ids=failure_ids, judgments=judgments, pjudgment=pjudgment, end_time=end_time, start_time=start_time, ai_result=ai_result, aoi_start_time=aoi_start_time, aoi_end_time=aoi_end_time, aoi_result=aoi_result)

        if page_size:
            offset_data = page_size * (page_index-1)
            panel_image_paginate = panel_images.offset(offset_data).limit(page_size).all()
            total_page = math.ceil(len(panel_images.all()) / page_size)
        else:
            # 如果不传 page_size,返回所有的 panel
            panel_image_paginate = panel_images.all()
            total_page = 1
        total_num = len(panel_images.all())

        predict_data = panel_failure_data(panel_image_paginate, session)

        return {"predict_data": predict_data, "total_page": total_page, "total_num": total_num}


# 全选导出
@router.post('/select-panel-code')
async def select_panel_code(item: SelectPanelCodeItem):
    lot_names = item.lot_names
    panel_ids = item.panel_ids
    failure_ids = item.failure_ids
    judgments = item.judgments if item.judgments else []
    pjudgment = item.pjudgment
    end_time = item.end_time
    start_time = item.start_time
    ai_result = item.ai_result
    aoi_result = item.aoi_result
    lot_code = item.lot_code
    # aoi生成的 panel 时间
    aoi_start_time = item.aoi_start_time
    aoi_end_time = item.aoi_end_time

    with InferSessionLocal() as session:
        panel_images = panel_filter(session, lot_names=lot_names, lot_code=lot_code, panel_ids=panel_ids, failure_ids=failure_ids, judgments=judgments, pjudgment=pjudgment, end_time=end_time, start_time=start_time, ai_result=ai_result, aoi_start_time=aoi_start_time, aoi_end_time=aoi_end_time, aoi_result=aoi_result)

        all_panel_code = []
        for panel_image in panel_images.all():
            all_panel_code.append(panel_image.panel_code)

    return {"all_panel_code": all_panel_code}


@router.post('/export-csv')
async def export_csv(item: SelectPanelCodeItem):
    lot_names = item.lot_names
    lot_code = item.lot_code
    panel_ids = item.panel_ids
    failure_ids = item.failure_ids
    judgments = item.judgments if item.judgments else []
    end_time = item.end_time
    start_time = item.start_time
    ai_result = item.ai_result
    aoi_result = item.aoi_result
    # 人工复判结果
    pjudgment = item.pjudgment
    aoi_start_time = item.aoi_start_time
    aoi_end_time = item.aoi_end_time

    # 条件查询是否也很耗时
    await loop.run_in_executor(None, export_csv_task, lot_names, lot_code, panel_ids, failure_ids, judgments, pjudgment, end_time, start_time, ai_result, aoi_start_time, aoi_end_time, aoi_result)
    
    return {"code": 0, "message": "生成 csv 成功"}


# 结果详情 -> 按缺陷图显示
@router.post('/failure-image')
async def failure_image(item: FailureImageItem):
    page_index = item.page_index
    page_size = item.page_size
    lot_name = item.lot_name
    panel_id = item.panel_id
    panel_code = item.panel_code
    lot_code = item.lot_code
    failure_ids = item.failure_ids
    judgments = item.judgments if item.judgments else []
    end_time = item.end_time
    start_time = item.start_time

    res = await loop.run_in_executor(None, failure_image_task, page_index, page_size, lot_name, lot_code, panel_id, panel_code, failure_ids, judgments, end_time, start_time)

    return res


# 通过一个检测点图片,获取该监测点图片所在的 panel 图片上的所有检测点信息
@router.post('/image-detail')
async def image_detail(item: AOIImageItem):
    image_code = item.image_code

    with InferSessionLocal() as session:

        panel_image = session.query(InferPanelImage).filter_by(panel_image_code=image_code).first()
        panel_code = panel_image.panel_code

        panel = session.query(InferPanel).filter_by(panel_code=panel_code).first()
        item = {}
        item["detection_info"] = json.loads(panel_image.detection_info) if panel_image.detection_info else ""
        item["file_name"] = panel_image.image_name
        item["file_path"] = panel_image.image_path
        item["thumb_file_path"] = panel_image.thumb_file_path
        item["panel_id"] = panel.panel_id

        return item
    

# 人工复检-通过输入 panel id,获取该panel 图片上的所有检测点信息
@router.post('/panel-detail')
async def panel_detail(item: PanelItem):
    panel_id = item.panel_id
    lot_name = item.lot_name
    # 获取重复数据的第几条
    index = item.index

    with InferSessionLocal() as session:

        if lot_name:
            lot = session.query(Lot).filter(Lot.lot_name == lot_name).order_by(Lot.start_time.desc()).first()

            panel_images = session.query(InferPanel).filter(and_(InferPanel.panel_id == panel_id, InferPanel.lot_code == lot.lot_code)).order_by(InferPanel.start_time.desc()).all()
        else:
            panel_images = session.query(InferPanel).filter(InferPanel.panel_id == panel_id).order_by(InferPanel.start_time.desc()).all()

        if len(panel_images) == 0:
            res = {"code": 0, "message": "未检测出"}
            return res
        elif len(panel_images) == 1:
            res = {"code": 1, "mesage": "只检出一个", "total_num": 1}
        else:
            res = {"code": 2, "message": "检查出重复 panel", "total_num": len(panel_images)}

        panel_image = panel_images[index]
        
        item = {}

        lot_code = panel_image.lot_code

        lot = session.query(Lot).filter_by(lot_code=lot_code).first()

        lot_name = lot.lot_name
        material_name = session.query(Material).filter_by(material_code=panel_image.material_code).first().material_name

        item["detection_info"] = json.loads(panel_image.detection_info) if panel_image.detection_info else []
        item["panel_file_path"] = panel_image.file_path
        item["thumb_file_path"] = panel_image.thumb_file_path
        item["aoi_file_path"] = panel_image.aoi_file_path
        item["judgment"] = panel_image.judgment
        item["panel_id"] = panel_id
        item["panel_code"] = panel_image.panel_code
        item["aoi_failures"] = json.loads(panel_image.aoi_failures) if panel_image.aoi_failures else []
        item["lot_name"] = lot_name
        item["material_name"] = material_name
        item["img_roi"] = json.loads(panel_image.img_roi) if panel_image.img_roi else []

        res['panel']= item
        return res
    

# 人工复检-点击确定复判结果
@router.post('/panel-judge')
async def panel_judge(item: PanelJudgeItem):
    panel_code = item.panel_code
    # '人工复判结果, 0-未复判, 1-OK, 2-NG'
    judgment = item.judgment
    failure_code = item.failure_code
    username = item.username

    with InferSessionLocal() as session:

        panel_image = session.query(InferPanel).filter_by(panel_code=panel_code).first()

        panel_image.judgment = judgment

        if failure_code:
            panel_image.failure_code = failure_code
        else:
            failure_code = ""

        session.commit()

        return {"code": 0, "message": "复判成功"}


# 结果详情-按 penel 显示-导出
@router.post('/panel-export')
async def panel_export(item: PanelExportItem):
    panel_codes = item.panel_codes
    export_type = item.export_type

    await loop.run_in_executor(None, panel_export_task, panel_codes, export_type)          


    return {"code": 0, "message": "导出文件成功"}


# 清空 aoi 数据库
@router.get('/lot-delete-all')
async def lot_delete_all():
    with InferSessionLocal() as session:
        session.query(Lot).delete()
        session.query(InferPanelImage).delete()
        session.query(InferPanel).delete()
        session.commit()

        # delete_aoi_db()

        return "清空 aoi 数据库成功"


# 获取软件版本
@router.get('/version')
async def version():
    yolox_model1_version = yolox_model_path1.split("_v")[1].split("/")[0]
    yolox_model2_version = yolox_model_path2.split("_v")[1].split("/")[0]
    yolox_model3_version = yolox_model_path3.split("_v")[1].split("/")[0]
    cls_forModel2_model_version = cls_forWhite_model_path.split("_v")[1].split("/")[0]
    cls_forRules_model_version = cls_forRules_model_path.split("_v")[1].split("/")[0]
    package_version = jd_package.split("jd_package_oqc-")[1].split("-")[0]
    all_version = {"yolox_model1_version": yolox_model1_version, "yolox_model2_version": yolox_model2_version, "yolox_model3_version": yolox_model3_version, "cls_forModel2_model_version": cls_forModel2_model_version, "cls_forRules_model_version": cls_forRules_model_version, "package_version": package_version}

    return all_version


# 上传 csv 文件,并解析
@router.post('/upload-csv')
async def upload_csv(csv_files: List[UploadFile], item: UploadCsvItem  = Body(...)):
    lots = item.lots
    # 按照日期时间排序, 从大到小排序
    lots.sort(key=lambda item:item['end_time'], reverse=True)

    future =  loop.run_in_executor(None, update_lot_from_csv, lots, csv_files)

    # Wait for the Future object to complete and get the result
    result = await future

    if result[0]:
        return {"code": 0, "message": "更新人工复检成功", "panel_updata": result[1]}
    else:
        return {"code": 1, "message": "更新人工复检失败"}
    

# 上传 csv 文件,并解析
@router.post('/upload-mes')
async def upload_mes(item: PanelMesJudgeItem):
    judge_info = item.judge_info

    with InferSessionLocal() as session:
        for judge_item in judge_info:
            panel_image = session.query(InferPanel).filter(InferPanel.panel_code==judge_item[0]).first()
            panel_image.judgment = judge_item[1]

        session.commit()

    return {"code": 0, "msg": "更新成功"}


# 返回所有物料
@router.get('/material')
async def material():
    all_material = []
    with InferSessionLocal() as session:
        materials = session.query(Material).all()
        for material in materials:
            item = {}
            item["material_name"] = material.material_name
            item["material_code"] = material.material_code
            item["background_image"] = material.background_image
            all_material.append(item)
        return {"materials": all_material}
    

# 所有 panel 图片上绘制检测点
@router.post('/panel-image-detail')
async def panel_image_detail(item: PanelImageItem):
    material_names = item.material_names
    failure_ids = item.failure_ids
    start_time = item.start_time
    end_time = item.end_time
    page_index = item.page_index
    page_size = item.page_size

    with InferSessionLocal() as session:
        # 只显示 NG 的图片
        all_panel_images = []

        panel_images = panel_filter(session, material_names=material_names, start_time_contain=start_time, end_time_contain=end_time)
        panel_images = panel_images.filter(InferPanel.aoi_result==2)

        if failure_ids:
            for panel_image in panel_images.all():
                panel_code = panel_image.panel_code
                failure_images = session.query(InferPanelImage).filter_by(panel_code=panel_code).filter(InferPanelImage.failure_id.in_(failure_ids)).all()
                
                if failure_images:
                    item = {}
                    # ok 的图片不展示
                    try:
                        item["detection_info"] = json.loads(panel_image.detection_info) if panel_image.detection_info else []
                    except Exception:
                        continue
                    item["thumb_file_path"] = panel_image.thumb_file_path
                    item["panel_id"] = panel_image.panel_id
                    item["server_host"] = panel_image.server_host
                    all_panel_images.append(item)
        else:
            for panel_image in panel_images:
                item = {}
                # ok 的图片不展示
                try:
                    item["detection_info"] = json.loads(panel_image.detection_info) if panel_image.detection_info else []
                except Exception:
                    continue
                item["thumb_file_path"] = panel_image.thumb_file_path
                item["panel_id"] = panel_image.panel_id
                item["server_host"] = panel_image.server_host
                all_panel_images.append(item)

        if page_size:
            offset_data = page_size * (page_index-1)
            panel_image_paginate = all_panel_images[offset_data: page_size * page_index]
            total_page = math.ceil(len(all_panel_images) / page_size)
        else:
            # 如果不传 page_size,返回所有的 panel
            panel_image_paginate = all_panel_images
            total_page = 1

        total_num = len(all_panel_images)
            
        return {"panel_images": panel_image_paginate, "total_page": total_page, "total_num": total_num}


# 所有 panel 图片上的使用 矩形框 绘制检测点
@router.post('/panel-box-heatmap')
async def panel_box_heatmap(item: PanelImageItem):
    material_name = item.material_name
    failure_ids = item.failure_ids
    start_time = item.start_time
    end_time = item.end_time

    res = await loop.run_in_executor(None, panel_box_heatmap_task, material_name, failure_ids, start_time, end_time)

    return res


# 所有 panel 图片上的使用 矩形框 绘制检测点
@router.post('/panel-pixel-heatmap')
async def panel_pixel_heatmap(item: PanelImageItem):
    material_name = item.material_name
    failure_ids = item.failure_ids
    start_time = item.start_time
    end_time = item.end_time

    res = await loop.run_in_executor(None, panel_pixel_heatmap_task, material_name, failure_ids, start_time, end_time)

    return res


# 结果详情,按 lot 显示
@router.post('/lot-detail-by-day')
async def lot_detail_by_day(item: PanelImageItem):
    end_time = item.end_time 
    start_time = item.start_time
    material_names = item.material_names
    
    res = {}

    with InferSessionLocal() as session:
        lots = session.query(Lot)
        # 前端选择的时间和数据库的时间会相差 8 个时区
        if start_time:

            # 按天拆分时间段
            time_list = {}
            
            

            current_time = start_time

            while current_time <= end_time:
                current_end_time = current_time + timedelta(days=1)
                current_end_time = current_end_time.replace(hour=0, minute=0, second=0, microsecond=0)

                current_date = current_time.strftime('%Y-%m-%d')

                if current_end_time<=end_time:
                    time_list[current_date] = [current_time, current_end_time]

                else:
                    time_list[current_date] = [current_time, end_time]

                current_time = current_end_time


            lots = lots.filter(Lot.start_time >= start_time).filter(Lot.end_time <= end_time)

            # 对 start_time 进行按日期分组, 同一天的会放在一组
            all_day_time = session.query(func.date_format(Lot.start_time, '%Y-%m-%d').label('date')).filter(Lot.start_time.between(start_time, end_time)).group_by('date').all()
        else:
            all_day_time = session.query(func.date_format(Lot.start_time, '%Y-%m-%d').label('date')).group_by('date').all()

        lot_data = []

        for day_time in all_day_time:
            day_time = day_time[0]

            # 某一天
            if start_time:
                s_time, e_time = time_list[day_time]
                lots = session.query(Lot).filter(Lot.start_time.between(s_time, e_time))
            else:
                lots = session.query(Lot).filter(func.date_format(Lot.start_time, '%Y-%m-%d')==day_time)

            if material_names:
                lots = get_material_lots(material_names, lots)

            all_panel_num = 0
            all_ai_accuracy = 0
            all_aoi_accuracy = 0
            all_judgement_accuracy = 0

            # 统计每天的 item
            lot_item = {}
            for lot in lots.all():

                panels = session.query(InferPanel).filter(InferPanel.lot_code == lot.lot_code)

                panel_num = session.query(func.count(InferPanel.panel_code)).filter(InferPanel.lot_code == lot.lot_code).scalar()
                all_panel_num += panel_num
                
                aoi_accuracy = 0
                ai_accuracy = 0
                judgement_accuracy = 0

                for panel in panels:
                    aoi_result = panel.aoi_result
                    ai_result = panel.ai_result
                    judgment = panel.judgment

                    # 如果 aoi 检测是正确的图片
                    if aoi_result == 1:
                        aoi_accuracy += 1

                    # 如果 ai 检测是正确的图片
                    if ai_result == 1:
                        ai_accuracy += 1

                    if judgment == 1:
                        judgement_accuracy += 1

                all_aoi_accuracy += aoi_accuracy
                all_ai_accuracy += ai_accuracy
                all_judgement_accuracy += judgement_accuracy

            # 物料总数
            lot_item["panel_num"] = all_panel_num

            if all_panel_num == 0:
                continue
            # 同一天的 aoi 良率
            lot_item["aoi_accuracy_rate"] = int(Decimal(all_aoi_accuracy/all_panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            # 同一天的 ai 良率
            lot_item["ai_accuracy_rate"] = int(Decimal(all_ai_accuracy/all_panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            # 同一天的人工复判良率
            lot_item["judgement_accuracy"] = int(Decimal(all_judgement_accuracy/all_panel_num).quantize(Decimal("0.01"), rounding="ROUND_HALF_UP")*100)
            lot_item["day_time"] = day_time


            lot_data.append(lot_item)
        res["lot_per_day"] = lot_data

        return res


@router.get('/conf')
async def get_infer_type():
        config = Config()
        config.read(os.path.join(root_path, 'config', 'server.ini'))
        infer_type = config.getint('lot', 'infer_type')
        ctype = config.getint('clear', 'ctype')
        scp_type = config.getint('lot', 'scp_type')
        scp_interval = config.getint('lot', 'scp_interval')
        delete_passwd = config.get('lot', 'delete_passwd')
        return {"infer_type": infer_type, "ctype": ctype,"scp_type": scp_type, "scp_interval": scp_interval, "delete_passwd": delete_passwd}


@router.post('/log/all')
async def get_log(item: LogItem):
    index = item.index
    
    if index == 0:
        log_file = os.path.join(os.path.dirname(root_path), "logs", "json.log")
    else:
        date_str = (datetime.utcnow() + timedelta(hours=8) + timedelta(days = -index)).strftime('%Y-%m-%d')
        log_file = os.path.join(os.path.dirname(root_path), "logs", f"json.log.{date_str}")
    
    if os.path.exists(log_file):
        with open(log_file) as f:
            log_lines = f.readlines()
            log_lines.reverse()
        
        logs = [json.loads(log_line) for log_line in log_lines]
    else:
        logs = []

    return {"log": logs}



@router.post('/log/add')
async def add_log(item: LogItem):
    logs = item.logs

    for log in logs:
        json_logger.info(json.dumps(log, ensure_ascii=False))

    return {"msg": "写入日志成功"}



@router.post('/rename')
async def rename_lot(item: LotRenameItem):
    lot_code = item.lot_code
    lot_name = item.lot_name
    comment = item.comment

    with InferSessionLocal() as session:
        lot = session.query(Lot).filter(Lot.lot_code==lot_code).first()

        # 修改 lot 名的同时, 所在的文件夹名也要修改
        lot.lot_name = lot_name
        lot.comment = comment
        
        session.commit()

        return {"msg": "lot 重命名成功"}

